Skip to content

彻底解决 Mac 与 Windows 协同开发中的 Git 换行符问题

让跨平台代码同步从此告别烦人的 ^M 和全文件飘红
—— 本文方案针对 Windows 为主团队的 CRLF 统一策略

📌 问题现象

作为一名同时使用 macOS 和 Windows 的开发人员,你一定遇到过这样的场景:

  • 在 Mac 上愉快地写完代码,push 到仓库;
  • 换到 Windows 上 git pull,什么都没改,但 git status 却显示大量文件被修改
  • 执行 git diff 看到满屏的 ^M 字符,或者整个文件被标记为“全部删除+全部新增”;
  • 代码审查时,PR 中夹杂着成百上千行无意义的空白变更,真正的逻辑改动被淹没。

这正是跨平台换行符(line ending)不一致导致的经典问题。

🔍 根本原因

操作系统换行符转义表示
macOS / LinuxLF\n
WindowsCRLF\r\n

Git 默认行为:

  • 在 Windows 上检出代码时,可能自动将 LF 转换成 CRLF;
  • 在 macOS/Linux 上检出时,保持 LF;
  • 提交时,Git 又会根据 core.autocrlf 配置决定是否转换。

当 Mac 用户提交的文件是 LF,Windows 用户拉取后被转成 CRLF,再改几个字符保存,就会产生大量无关换行符的 diff

🎯 方案选择:根据团队主流系统决定

网上的大多数教程会推荐统一使用 LF,因为这是 Linux/macOS 以及云原生 CI/CD 环境的默认标准。但如果你的团队主力开发机是 Windows,强行要求所有人使用 LF 反而会带来很多不便:

  • Windows 上很多老旧工具(甚至某些公司内部脚本)对 LF 支持不佳;
  • 部分 Windows 程序员习惯 CRLF,强制 LF 会导致他们本地看到大量文件被“修改”;
  • 切换成本高,需要一次性规范化整个仓库。

因此,最务实的做法是:以 Windows 为主,统一使用 CRLF。这样 Windows 同事无任何感知,Mac 同事只要做好配置,也能完美适配。

✅ 解决方案:使用 .gitattributes 强制 CRLF

与其要求每个团队成员手动设置 git config,不如在项目仓库中声明换行符规则.gitattributes 文件会跟随代码一起版本控制,优先级最高,一劳永逸。

1️⃣ 创建 .gitattributes 文件(CRLF 版)

在项目根目录下新建 .gitattributes,写入以下内容(核心:* text=auto eol=crlf):

gitattributes
# 所有文本文件统一使用 CRLF(Windows 原生格式)
* text=auto eol=crlf

# 特殊脚本文件(如需在 Linux/macOS 运行,必须保持 LF)
# 如果你的项目没有这类脚本,可以不加
*.sh text eol=lf
*.bash text eol=lf

# Windows 批处理文件已经是 CRLF,保持即可
*.bat text eol=crlf
*.cmd text eol=crlf

# 二进制文件禁止任何转换
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.pdf binary
*.zip binary
*.tar binary
*.gz binary
*.mp4 binary
*.mp3 binary

解释

  • * text=auto eol=crlf:所有文本文件,无论原始格式如何,在检入仓库时都会被规范化,检出到工作区时强制转换为 CRLF。
  • 对于 .sh 等需要在 Linux/macOS 上执行的脚本,单独覆盖为 lf,避免执行报错(如果你没有这类文件,可以忽略)。

2️⃣ 提交配置文件并规范化现有仓库

bash
# 先把 .gitattributes 本身提交
git add .gitattributes
git commit -m "Add .gitattributes to enforce CRLF line endings"

# 关键步骤:强制 Git 按新规则重新处理所有文件
git add --renormalize .

# 提交这次规范化变更
git commit -m "Normalize all line endings to CRLF"

# 推送到远程仓库
git push

⚠️ 注意git add --renormalize . 可能会修改大量文件(尤其是原本混用 LF 的文件)。建议在独立分支上操作,并通知团队成员。

3️⃣ Mac 同事的额外配置

对于使用 macOS 的开发者,需要让 Git 在提交时正确处理 CRLF 文件。运行以下命令:

bash
git config --global core.autocrlf input

这条命令告诉 Git:在 macOS 上,检出时不转换(保持 CRLF 原样),但提交时自动将 CRLF 转换为 LF 存入仓库。配合 .gitattributeseol=crlf,效果是:工作区始终是 CRLF,仓库内也是 CRLF(因为提交时从 CRLF 转成 CRLF,无变化)。

Windows 同事无需任何额外配置core.autocrlf 设为 true 即可(通常 Git for Windows 安装时已默认设置)。

4️⃣ 团队成员同步

其他成员拉取这次提交后,也需要运行一次规范化命令:

bash
git pull
git add --renormalize .
# 如果没有本地未提交的修改,也可以直接 git reset --hard HEAD

🧪 验证是否生效

  • 查看某个文件的换行符类型(Linux/macOS):
    bash
    cat -A src/main.js | head -1
    # 输出行尾为 ^M$ 表示 CRLF,输出 $ 表示 LF
  • 在 VS Code 中:打开文件,右下角状态栏会显示 CRLFLF
  • 检查 Git 对文件的属性解读
    bash
    git check-attr -a src/main.js
    # 预期输出: src/main.js: text: set
    #          src/main.js: eol: crlf

🩹 临时手段:在 git diff 中忽略换行符

有时候你只是想快速查看代码逻辑变化,不想看到铺天盖地的空白差异。Git 提供了几个非常有用的参数:

bash
# 忽略所有空白字符(包括换行符、行尾空格等)
git diff -w

# 仅忽略行尾空白符(空格、Tab)
git diff --ignore-space-at-eol

# 忽略行尾回车符 CR(即忽略 ^M)
git diff --ignore-cr-at-eol

你也可以给它们设置别名:

bash
git config --global alias.diffw "diff -w"
git config --global alias.diffcr "diff --ignore-cr-at-eol"

注意:这些命令只影响 diff 的显示结果,不解决根本问题。长期方案仍然要使用 .gitattributes

📚 总结:Windows 主力团队的推荐配置

角色必须配置可选配置
项目仓库添加 .gitattributes 并设置 * text=auto eol=crlf
Windows 开发者确保 git config core.autocrlftrue(通常默认)
macOS 开发者git config --global core.autocrlf input编辑器设置默认换行符为 CRLF(如 VS Code 中 "files.eol": "\r\n"
Linux 开发者git config --global core.autocrlf input同上

为什么我们选择 CRLF 而不是 LF?

  • 团队现状:90% 的开发机是 Windows,他们不希望改变已有的 CRLF 习惯。
  • 工具兼容:部分公司内部脚本、老旧 IDE、命令行工具严格依赖 CRLF。
  • 改动最小:统一为 CRLF 后,Windows 同事看到零变化,只需 Mac 同事做一次配置和仓库规范化。

只要团队不涉及大量在 Linux 服务器上直接编辑文件(通常通过 CI/CD 自动处理),CRLF 方案稳定可靠。

🚀 最佳实践建议

  1. 新项目:从一开始就放入 .gitattributes,避免混乱。
  2. 老项目:找一个合适的时间点(如版本发布后),单独提交一个“规范化换行符为 CRLF”的 commit,并在 PR 中说明。
  3. 文档化:在团队 README 中写明换行符规范,让新成员第一时间知晓。

从此,无论是 Mac、Windows 还是偶尔的 Linux 开发者,提交的代码换行符都将整齐划一为 CRLF,git diff 中再也看不到无意义的 ^M 符号。让开发者专注于真正的代码逻辑,而不是被格式差异浪费生命。


写在最后:换行符问题看似微小,却足以让跨平台团队每周浪费数小时。希望这篇博客能帮助你一次性解决这个痛点。如果觉得有用,欢迎分享给更多被这个问题困扰的朋友。

最近更新